<template>
  <div class="vex-table" style="display: flex; flex-direction: column; width: 100%; height: 100%">
    <div v-if="showToolbar !== false" class="vex-table-toolbar" style="flex: none">
      <vxe-toolbar ref="toolbarRef" custom style="background: none">
        <template #buttons><slot name="table-toolbar-buttons" /></template>
      </vxe-toolbar>
    </div>
    <div class="vex-table-wrap" style="flex: auto; height: auto; min-height: 0">
      <vxe-table ref="tableRef" v-bind="tableAttrs" :loading="loading" :data="data.list">
        <template #empty>
          <div class="vex-table-empty"><c-empty :text="emptyText" /></div>
        </template>
        <vxe-column v-if="showIndexColumn !== false" type="seq" title="序号" width="60" align="center" />
        <vxe-column v-if="showRadioColumn !== false" type="radio" title="单选" width="80" align="center" />
        <vxe-column v-if="showCheckboxColumn !== false" type="checkbox" title="全选" width="90" align="center" />
        <template v-for="item of tableColumns" :key="item.field">
          <vxe-column v-bind="item">
            <template #default="{ column, row, rowIndex, text }">
              {{ ((text = getText({ column: item, row })), null) }}
              <slot :name="column.field" :index="rowIndex" :column="column" :scope="row" :text="text">{{ text }}</slot>
            </template>
          </vxe-column>
        </template>
      </vxe-table>
    </div>
    <vxe-pager
      v-if="showPage"
      v-model:current-page="current"
      v-model:page-size="pageSize"
      :total="data.total"
      :loading="loading"
      :background="true"
      v-bind="pagerOptions"
      class="vex-table-pager"
      style="flex: none"
      @page-change="pageChange"
    >
    </vxe-pager>
  </div>
</template>

<script>
import { NONE_TEXT } from '@gis/lib/config/index.js';
import { ref, computed, onMounted, watch, onUnmounted } from 'vue';
import { remove, merge, omit, get } from 'lodash-es';
import { VxeTable, VxeColumn, VxeToolbar, VxePager } from 'vxe-table';
import { handleTableColumns } from './tableUtils.js';
import CEmpty from '@gis/lib/components/CEmpty.vue';

export default {
  name: 'VexTable',
  components: { CEmpty, VxeTable, VxeColumn, VxeToolbar, VxePager },
  emits: ['update:checkedRowKeys', 'update:checkedRowKey', 'checkboxChange', 'radioChange'],
  props: {
    fetch: { type: Function, default: undefined },
    fetchParams: { type: Object, default: () => undefined },
    dataSource: { type: Array, default: undefined },
    columns: { type: Array, default: undefined },
    rowKey: { type: String, default: '_row_id' },
    noneText: { type: String, default: NONE_TEXT },
    emptyText: { type: String, default: '~暂无数据~' },
    pagination: { type: [Object, Boolean], default: undefined },
    replaceFields: { type: Object, default: undefined },
    checkedRowKeys: { type: Array, default: undefined },
    checkedRowKey: { type: [String, Number], default: undefined },
    showIndexColumn: { type: Boolean, default: true },
    showRadioColumn: { type: Boolean, default: false },
    showCheckboxColumn: { type: Boolean, default: false },
    showToolbar: { type: Boolean, default: true },
  },
  setup(props, { attrs, emit }) {
    let fetchParams = {};
    const tableRef = ref(null);
    const toolbarRef = ref(null);
    const loading = ref(false);
    const data = ref({ list: [], total: 0 });
    const paginationFields = {
      request: {
        currentKey: 'page_number',
        pageSizeKey: 'page_size',
      },
      response: {
        totalKey: 'total',
        currentKey: 'page',
        pageSizeKey: 'pageSize',
      },
    };
    const fields = merge({}, paginationFields, props.replaceFields);
    const showPage = computed(() => props.pagination !== false);
    const current = ref(get(props, 'pagination.current', 1));
    const pageSize = ref(get(props, 'pagination.pageSize', 10));
    const tableConfig = {
      border: true,
      round: true,
      stripe: true,
      height: 'auto',
      autoResize: true,
      showHeader: true,
      headerAlign: 'center',
      keyboardConfig: { isArrow: false, isDel: false, isEnter: false, isTab: false, isEdit: false, isChecked: false },
      tooltipConfig: { showAll: true, enterable: true },
      columnConfig: { resizable: true },
      rowConfig: { keyField: props.rowKey, isHover: true },
      seqConfig: {
        seqMethod({ rowIndex }) {
          return showPage.value ? (current.value - 1) * pageSize.value + (rowIndex + 1) : rowIndex + 1;
        },
      },
      // gis页面上因为highlight：true、表格上都会加上.row--checked
      checkboxConfig: {
        checkRowKeys: props.checkedRowKeys,
        highlight: false,
        range: false,
        trigger: 'row',
      },
      radioConfig: { checkRowKey: props.checkedRowKey, highlight: false, trigger: 'row' },
      onCheckboxAll: onCheckboxChange,
      onCheckboxChange: onCheckboxChange,
      onRadioChange: onRadioChange,
    };
    const tableAttrs = merge({}, tableConfig, omit(attrs, ['class', 'style']));
    const tableColumns = computed(() => {
      return handleTableColumns(props.columns);
    });
    const pagerLayouts = ['PrevJump', 'PrevPage', 'JumpNumber', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'Total'];
    const pagerOptions = {
      layouts: get(props, 'pagination.layouts', pagerLayouts),
      size: get(props, 'pagination.size'),
      pageSizes: get(props, 'pagination.pageSizeOptions'),
      autoHidden: get(props, 'pagination.hideOnSinglePage'),
      align: get(props, 'pagination.align', 'right'),
    };

    if (get(props, 'pagination.showSizeChanger') === false) {
      remove(pagerOptions.layouts, (v) => v === 'Sizes');
    }
    if (get(props, 'pagination.showQuickJumper') === false) {
      remove(pagerOptions.layouts, (v) => v === 'FullJump');
    }
    if (get(props, 'pagination.showTotal') === false) {
      remove(pagerOptions.layouts, (v) => v === 'Total');
    }

    async function getDataAsync(params) {
      if (Array.isArray(props.dataSource)) {
        return;
      }
      if (typeof props.fetch === 'function') {
        loading.value = true;
        try {
          // 列表默认有值
          const res = await props.fetch(params);
          const list = get(res, 'data');
          const total = get(res, 'total');
          data.value = {
            list: Array.isArray(list) ? list : [],
            total: Number.isFinite(total) ? total : 0,
          };
        } catch (e) {
          console.error(e);
        }
        loading.value = false;
      }
    }
    function pageChange(data) {
      fetchParams = Object.assign({}, fetchParams, props.fetchParams, {
        [fields.request.currentKey]: get(data, 'currentPage'),
        [fields.request.pageSizeKey]: get(data, 'pageSize'),
      });
      getDataAsync(fetchParams);
    }
    async function load(params) {
      fetchParams = Object.assign({}, fetchParams, props.fetchParams, params, {
        [fields.request.currentKey]: current.value,
        [fields.request.pageSizeKey]: pageSize.value,
      });
      await getDataAsync(fetchParams);
    }
    function refresh(params) {
      load(params);
    }
    function reload(params) {
      current.value = get(props, 'pagination.current', 1);
      load(params);
    }
    function dispatch() {
      const name = arguments[0];
      const $table = tableRef.value;
      if (name && $table && typeof $table[name] === 'function') {
        const args = Array.prototype.slice.call(arguments, 1);
        return $table[name].apply($table, args);
      }
    }
    function onCheckboxChange() {
      const records = dispatch('getCheckboxRecords');
      if (Array.isArray(records)) {
        const keys = records.map((item) => get(item, props.rowKey));
        emit('update:checkedRowKeys', keys);
        emit('checkboxChange', records);
      }
    }
    function onRadioChange() {
      const record = dispatch('getRadioRecord');
      if (record) {
        const key = get(record, props.rowKey);
        emit('update:checkedRowKey', key);
        emit('radioChange', record);
      }
    }
    function getText({ column, row }) {
      let field = get(column, 'field');
      let value = get(row, field);
      let tempStr = String(field).match(/\{[^\{\}]+\}/g);
      let formatter = get(column, 'formatter', get(column, 'format', get(column, 'customRender')));
      if (typeof formatter !== 'function') {
        formatter = (v) => v;
      }
      if (tempStr && tempStr.length) {
        value = tempStr.reduce((res, item) => {
          let val = get(row, item.replace(/[{\s}]/g, '')) || '';
          return res.replace(item, formatter(val, row, column));
        }, field);
      } else {
        value = formatter(value, row, column);
      }
      if (value !== undefined && value !== null && value !== '') {
        return value;
      }
      return get(column, 'noneText', get(props, 'noneText', NONE_TEXT));
    }

    watch(
      () => props.dataSource,
      () => {
        if (Array.isArray(props.dataSource)) {
          data.value = {
            list: props.dataSource,
            total: props.dataSource.length,
          };
        }
      },
      { immediate: true }
    );

    onMounted(() => {
      if (props.showToolbar !== false) {
        // 将表格和工具栏进行关联
        const $table = tableRef.value;
        const $toolbar = toolbarRef.value;
        if ($table && $toolbar) {
          $table.connect($toolbar);
        }
      }
    });

    onUnmounted(() => {
      fetchParams = null;
    });

    return {
      load,
      reload,
      refresh,
      getText,
      dispatch,
      pageChange,
      tableRef,
      toolbarRef,
      loading,
      data,
      current,
      pageSize,
      pagerOptions,
      showPage,
      tableColumns,
      tableAttrs,
    };
  },
};
</script>

<style lang="less">
.vex-table {
  .vex-table-toolbar {
    padding: 0;
    .vxe-toolbar {
      padding: 1em 0;
    }
  }
  .vex-table-wrap {
    .vxe-table.is--empty {
      width: 100%;
      height: 100%;
      .vxe-table--empty-placeholder {
        width: 100%;
        height: 100%;
        .vxe-table--empty-content {
          .vex-table-empty {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            text-align: center;
          }
        }
      }
    }
  }
  .vex-table-pager {
    padding: 0 0.6em;
  }
}
</style>
